#include <QSettings>
#include <QMessageBox>
#include <QFile>
#include <QDebug>
#include <QTextCodec>
#include <QDir>

#include "CONST.h"

#include "MainWindow.h"
#include "ui_MainWindow.h"

#include "AutoRun.h"
#include "fmAbout.h"
#include "fmHelp.h"
#include "appSettings.h"
#include "auxiliaries_func.h"

LAutoRun* LAutoRun::instance = 0;
ApplicationSettings* ApplicationSettings::instance = 0;

//QString ver = QCoreApplication::applicationVersion();


//----------------------------------------------------------------------------------------
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow) {

    ui->setupUi(this);

    firstStartApp = true;

    LAutoRun::getInstance()->setApplicationName(QCoreApplication::applicationName());
    ApplicationSettings::getInstance()->setRegGroupProperties(Manufacturer, applicationName);

    if(!ApplicationSettings::getInstance()->getBoolProperty(groupSwitches, propertyNotFirstRunInThisOS)) {
        ui->chkbxAutorun->setChecked(true);
        ui->chkbxAutoCheckNewDevice->setChecked(true);
        ApplicationSettings::getInstance()->setSettingProperty(groupSwitches, propertyNotFirstRunInThisOS, true);
        ApplicationSettings::getInstance()->setSettingProperty(groupSwitches, propertyAutoSwitch, true);
        LAutoRun::getInstance()->setAutoRunState(true);
    }
    else {
        ui->chkbxAutorun->setChecked(LAutoRun::getInstance()->isInAutoRun());
        ui->chkbxAutoCheckNewDevice->setChecked(ApplicationSettings::getInstance()->getBoolProperty(groupSwitches, propertyAutoSwitch));
    }

    trayIconMenu = new QMenu(this);
    menuGroupTmpActions = new QActionGroup(this);
    menuGroupTmpActions->setExclusive(true);

    vectorOfAction.clear();
    checkableList.clear();

    createTrayIcon();

    connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
            this, SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));

    trayIcon->setVisible(true);
    mDevManager = new MDeviceManager(this);

    setWindowFlags(Qt::MSWindowsFixedSizeDialogHint |
                   Qt::WindowSystemMenuHint |
                   Qt::WindowStaysOnTopHint);

}

//----------------------------------------------------------------------------------------
MainWindow::~MainWindow() {
    delete trayIconMenu;
    delete menuGroupTmpActions;
    delete ui;
}

//----------------------------------------------------------------------------------------
void MainWindow::changeEvent(QEvent *e) {
    QMainWindow::changeEvent(e);
    switch (e->type()) {
    case QEvent::LanguageChange:
        ui->retranslateUi(this);
        break;
    default:
        break;
    }
}

//----------------------------------------------------------------------------------------
void MainWindow::closeEvent(QCloseEvent *event) {
    if (trayIcon->isVisible()) {
        hide();
    }
}

//----------------------------------------------------------------------------------------
void MainWindow::iconActivated(QSystemTrayIcon::ActivationReason reason) {
    switch (reason) {
    case QSystemTrayIcon::Context:
        trayIconMenu->activateWindow();
        break;
    case QSystemTrayIcon::DoubleClick:
        this->showNormal();
        //        show();
        break;
    default:
        ;
    }
}

//----------------------------------------------------------------------------------------
void MainWindow::showMessageTrayBaloon(QString &txt) {
    QSystemTrayIcon::MessageIcon icon = QSystemTrayIcon::MessageIcon(QSystemTrayIcon::Information);
    trayIcon->showMessage(Manufacturer, txt, icon, 5000);
}

//----------------------------------------------------------------------------------------
void MainWindow::about() {
    fmAbout *win = new fmAbout();
    win->setAttribute(Qt::WA_DeleteOnClose);
    setWindowCenter(win);
    setWindowFixedCloseOnlyStayOnTop(win);
    win->show();
}

//----------------------------------------------------------------------------------------
void MainWindow::help() {
    fmHelp *win = new fmHelp();
    win->setAttribute(Qt::WA_DeleteOnClose);
    setWindowCenter(win);
    setWindowFixedCloseOnlyStayOnTop(win);
    win->show();
}

//----------------------------------------------------------------------------------------
void MainWindow::createMainActions() {
    menuGroupMainAction = new QActionGroup(NULL);

    minimizeAction = new QAction(tr("Mi&nimize"), this);
    connect(minimizeAction, SIGNAL(triggered()), this, SLOT(hide()));

    restoreAction = new QAction(tr("&Restore"), this);
    connect(restoreAction, SIGNAL(triggered()), this, SLOT(showNormal()));

    menuHelp = new QAction(tr("&Help"), this);
    connect(menuHelp, SIGNAL(triggered()), this, SLOT(help()));

    aboutAction = new QAction(tr("&About"), this);
    connect(aboutAction, SIGNAL(triggered()), this, SLOT(about()));

    quitAction = new QAction(tr("&Quit"), this);
    connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));

    menuGroupMainAction->addAction(minimizeAction);
    menuGroupMainAction->addAction(restoreAction);
    menuGroupMainAction->addAction(menuHelp);
    menuGroupMainAction->addAction(aboutAction);
    menuGroupMainAction->addAction(quitAction);
}

//----------------------------------------------------------------------------------------
QString MainWindow::readMaDecoderPortSetting() {
    QTextCodec *codec;
    QString comPortNum("");

#if defined(Q_WS_WIN)
    codec = QTextCodec::codecForName(codecCP1251.toLocal8Bit().data());
#else
    codec = QTextCodec::codecForName(codecUTF8.toLocal8Bit().data());
#endif

    QString iniFile = QApplication::applicationDirPath() + "/" + fileNameF3Set;

    if(QFile::exists(iniFile)) {
        QSettings settingsMaDecoder(iniFile, QSettings::IniFormat);
        settingsMaDecoder.setIniCodec(codec);
        settingsMaDecoder.beginGroup(f3SetGroupConfig);
        comPortNum = settingsMaDecoder.value(codec->fromUnicode(f3SetPropComPort)).toString();
        settingsMaDecoder.endGroup();
        return comPortNum;
    }
    return "";
}

//----------------------------------------------------------------------------------------
QString MainWindow::getCOMPortNameSetting() {
    QString res = sCOM + readMaDecoderPortSetting();
    return res;
}

//----------------------------------------------------------------------------------------
void MainWindow::reconstructTrayMenu(connDevicesType &devList,
                                     avSerPort &portList,
                                     QString &captionOfSerialPort,
                                     devStatus statusConn,
                                     bool isNeedManufacturer) {
    if(menuGroupTmpActions) {
        delete menuGroupTmpActions;
        menuGroupTmpActions = new QActionGroup(this);
        menuGroupTmpActions->setExclusive(true);
    }

    if(vectorOfAction.size() > 0) {
        for(int i = 0; i != vectorOfAction.size(); i++) {
            delete vectorOfAction[i];
        }
        vectorOfAction.clear();
    }

    avSerPort::const_iterator itPort = portList.constBegin();
    while(itPort != portList.constEnd()) {
        tmpMenuItem = new QAction(*itPort, this);
        tmpMenuItem->setObjectName(*itPort);
        tmpMenuItem->setCheckable(true);

        QObject::connect(tmpMenuItem, SIGNAL(triggered()), this, SLOT(menuSelect()));
        vectorOfAction.append(tmpMenuItem);

        menuGroupTmpActions->addAction(tmpMenuItem);
        ++itPort;
    }

    connDevicesType::const_iterator itDev = devList.constBegin();
    while (itDev != devList.constEnd()) {
        QString tmpV1 = itDev.value().description;
        QString tmpV3 = itDev.value().serialPort;
        bool checked  = itDev.value().checked;

        QString menuItem = tmpV1;
        menuItem += " (";
        menuItem += tmpV3;
        menuItem += ")";

        tmpMenuItem = new QAction(menuItem, this);
        tmpMenuItem->setObjectName(tmpV3);
        tmpMenuItem->setCheckable(true);

        if(checked && ui->chkbxAutoCheckNewDevice->isChecked()) {
            tmpMenuItem->setChecked(true);
            saveCOMPortSetting(tmpMenuItem->objectName());
            if(checkableList.contains(tmpMenuItem->objectName()))
                checkableList.removeAll(tmpMenuItem->objectName());
            checkableList.push_back(tmpMenuItem->objectName());
        }

        QObject::connect(tmpMenuItem, SIGNAL(triggered()), this, SLOT(menuSelect()));
        vectorOfAction.append(tmpMenuItem);

        menuGroupTmpActions->addAction(tmpMenuItem);
        ++itDev;
    }

    if(ui->chkbxAutoCheckNewDevice->isChecked()) {
        if( ((int)statusConn == (int)deviceWasAdded) ) {
            if(isNeedManufacturer) {
                if(selectLastCheckMenu())
                    return;
            }
            else { // another manufacturer
                if(!readCurrentSerialPort()) {
                    if(selectLastCheckMenu())
                        return;
                }
            }
        }

        if( ((int)statusConn == (int)deviceWasRemoved) ) {
            if(isNeedManufacturer) {

                if(menuGroupTmpActions->actions().count() == 0) {
                    checkableList.clear();
                    createMenuActions();
                    return;
                }

                checkableList.removeAll(captionOfSerialPort);

                if(checkableList.count() == 0) {
                    menuGroupTmpActions->actions().value(0)->setChecked(true);
                    saveCOMPortSetting(menuGroupTmpActions->actions().value(0)->objectName());
                    createMenuActions();
                    return;
                }

                if(readCurrentSerialPort()) {
                    saveCOMPortSetting(comPortNameF3Setting);
                    createMenuActions();
                    return;
                }

                if(selectLastCheckMenu())
                    return;
            }
            else { // another manufacturer
                checkableList.removeAll(captionOfSerialPort);
                if(!readCurrentSerialPort()) {
                    if(checkableList.count() > 0) {
                        checkableList.pop_back();
                        if(selectLastCheckMenu()) {
                            return;
                        }
                    }
                }
            }
        }
    }
    else { // autoswitch off
        for(int i = 0; i != menuGroupTmpActions->actions().count(); i++) {
            if(menuGroupTmpActions->actions().value(i)->objectName() ==
                    getCOMPortNameSetting()) {

                menuGroupTmpActions->actions().value(i)->setChecked(true);
                saveCOMPortSetting(menuGroupTmpActions->actions().value(i)->objectName());
                createMenuActions();
                return;
            }
        }
    }
    createMenuActions();
}

//----------------------------------------------------------------------------------------
bool MainWindow::selectLastCheckMenu() {
    if(checkableList.count() > 0) {
        for(int i = 0; i != menuGroupTmpActions->actions().count(); i++) {
            if(menuGroupTmpActions->actions().value(i)->objectName() ==
                    checkableList.value(checkableList.count()-1)) {

                menuGroupTmpActions->actions().value(i)->setChecked(true);
                saveCOMPortSetting(menuGroupTmpActions->actions().value(i)->objectName());
                createMenuActions();
                return true;
            }
        }
    }
    return false;
}

//----------------------------------------------------------------------------------------
bool MainWindow::readCurrentSerialPort() {
    comPortNameF3Setting = getCOMPortNameSetting();
    int k = menuGroupTmpActions->actions().count();
    for(int i = 0; i != k; i++) {
        QString itemName = menuGroupTmpActions->actions().value(i)->objectName();
        if(itemName == comPortNameF3Setting) {
            menuGroupTmpActions->actions().value(i)->setChecked(true);

            if(checkableList.contains(itemName))
                checkableList.removeAll(itemName);
            checkableList.push_back(itemName);

            return true; // found current serial port in current menu list
        }
    }
    return false; // not found current serial port in current menu list
}

//----------------------------------------------------------------------------------------
void MainWindow::checkMenuItemAtFirstStart() {
    if(firstStartApp) {
        readCurrentSerialPort();
        firstStartApp = false;
    }
}

//----------------------------------------------------------------------------------------
void MainWindow::createMenuActions() {
    trayIconMenu->clear();
    trayIconMenu->addActions(menuGroupTmpActions->actions());
    trayIconMenu->addSeparator();
    trayIconMenu->addActions(menuGroupMainAction->actions());

    checkMenuItemAtFirstStart();
}

//----------------------------------------------------------------------------------------
void MainWindow::createTrayIcon() {
    createMainActions();

    trayIcon = new QSystemTrayIcon(QIcon(":/appIcon.png"), this);
    trayIcon->setToolTip(toolTipTray);
    trayIcon->setContextMenu(trayIconMenu);
}

//----------------------------------------------------------------------------------------
quint16 MainWindow::getComPortNumber(const QString &comPort) {

    int sizeStr = comPort.length();

    if(sizeStr < 4)
        return 0;

    QString resNum("");

    for(int i = 3; i != comPort.count(); i++) {
        resNum.append(comPort[i]);
    }

    return resNum.toInt();
}

//----------------------------------------------------------------------------------------
void MainWindow::saveCOMPortSetting(const QString &comPortName) {

    quint16 comPortNum = getComPortNumber(comPortName);

    QTextCodec *codec;

#if defined(Q_WS_WIN)
    codec = QTextCodec::codecForName(codecCP1251.toLocal8Bit().data());
#else
    codec = QTextCodec::codecForName(codecUTF8.toLocal8Bit().data());
#endif

    QString iniFile = QApplication::applicationDirPath() + "/" + fileNameF3Set;

    QSettings settingsMaDecoder(iniFile, QSettings::IniFormat);
    settingsMaDecoder.setIniCodec(codec);
    settingsMaDecoder.beginGroup(f3SetGroupConfig);
    settingsMaDecoder.setValue(f3SetPropComPort, comPortNum);
    settingsMaDecoder.endGroup();

}

//----------------------------------------------------------------------------------------
void MainWindow::menuSelect() {
    if(QAction *action = qobject_cast<QAction*>(sender())) {
        if(checkableList.contains(tmpMenuItem->objectName()))
            checkableList.removeAll(tmpMenuItem->objectName());
        checkableList.push_back(action->objectName());

        saveCOMPortSetting(sender()->objectName());
    }

}

//----------------------------------------------------------------------------------------
void MainWindow::on_chkbxAutorun_stateChanged(int arg1) {
    if(arg1 == stateTrue)
        LAutoRun::getInstance()->setAutoRunState(true);
    else if(arg1 == stateFalse)
        LAutoRun::getInstance()->setAutoRunState(false);
}

//----------------------------------------------------------------------------------------
void MainWindow::on_chkbxAutoCheckNewDevice_stateChanged(int arg1) {
    if(arg1 == stateTrue)
        ApplicationSettings::getInstance()->setSettingProperty(groupSwitches, propertyAutoSwitch, true);
    else if(arg1 == stateFalse)
        ApplicationSettings::getInstance()->setSettingProperty(groupSwitches, propertyAutoSwitch, false);
}
